#include <iostream>
#include <cstdio>
#include <string>
#include <vector>
#include <queue>
#include <algorithm>

#define FOR(i,a,n) for(int i=a,_n(n);i<_n;++i)
#define REP(i,n) FOR(i,0,n)

const int INF = 1<<29;

using namespace std;
class Graph {
public:
    struct Edge {
    public:
        int vs, vt, flow, cap;
        Edge* next;

        void Set(int a, int b, int c, Edge* nt) {
            vs = a, vt = b, cap = c;
            next = nt;
            flow = 0;
        }

        inline int remain() {
            return cap - flow;
        }
    };
    Edge *edge, **head;
    int vn, arcn;

    Graph(int n, int m) {
        edge = new Edge[m + 10];
        vn = n + 1;
        arcn = 0;
        head = new Edge*[n + 10];
        fill(head, head + vn + 1, (Edge*) NULL);
    }

    ~Graph() {
        delete(head);
        delete(edge);
    }

    void AddArc(int vs, int vt, int cap) {
        edge[arcn].Set(vs, vt, cap, head[vs]);
        head[vs] = &edge[arcn++];
    }

    void AddFlow(int vs,int vt,int cap)
    {
        AddArc(vs,vt,cap);
        AddArc(vt,vs,0);
    }

    int MaxFlow(int vs, int vt) {
        vector<int> dist(vn + 10, 0);
        vector<int> cnt(vn + 10, 0);
        int ans = 0;
        vector<Edge*> pre(vn + 10, (Edge*)NULL);
        vector<Edge*> cur(vn + 10, (Edge*)NULL);
        REP(i, vn + 1) cur[i] = head[i];
        cnt[0] = vn;
        int pos = vs;
        Edge *ep;
        while (dist[vs] < vn) {
            for (ep = cur[pos]; ep; ep = ep->next)
                if (dist[pos] == dist[ep->vt] + 1 && ep->remain()) break;
            if (ep) {
               // printf("%d->%d\n", ep->vs, ep->vt);
                cur[pos] = ep;
                pre[ep->vt] = ep;
                pos = ep->vt;
                if (pos == vt) {
                    int minf = INF;
                    for (ep = pre[vt]; ep; ep = pre[ep->vs]) if (ep->remain() < minf) {
                            minf = ep->remain();
                            pos = ep->vs;
                        }
                    for (ep = pre[vt]; ep; ep = pre[ep->vs]) {
                        ep->flow += minf;
                        edge[(ep - edge)^1].flow -= minf;
                    }
                    ans += minf;
                }
            } else {
                if (--cnt[dist[pos]] == 0) break;
                dist[pos] = vn;
                for (ep = head[pos]; ep; ep = ep->next) {
                    if (dist[pos] > dist[ep->vt] + 1 && ep->remain())
                        dist[pos] = dist[ep->vt] + 1, cur[pos] = ep;
                }
                cnt[dist[pos]]++;
                if (pos != vs) pos = pre[pos]->vs;
                //printf("dist[%d]=%d\n", pos, dist[pos]);
            }
        }
       // printf("flow = %d\n",ans);
        return ans;
    }
};

inline int GetV(int x,int y,int& m)
{
    return x*m+y;
}

int main()
{
    int T;
    cin>>T;
    REP(ca,T)
    {
        int n,m,gc,sc;
        int sum = 0;
        cin>>n>>m>>gc>>sc;
        Graph g(n*m*2+10,2*m*n*20);
        int ss = n*m*2+4,tt = ss+1;
        int vn = m*n;
        REP(i,vn) g.AddFlow(i,i+vn,INF);
        REP(i,n)
        {
            bool isLeft = ((i&1)==0);
            REP(j,m)
            {
                int w,v = GetV(i,j,m);
                scanf("%d",&w);
                sum+=w;
                if(isLeft)
                {
                    g.AddFlow(ss,v,w);
                    if(i-1>=0) g.AddFlow(v,v-m+vn,gc);
                    if(i+1<n) g.AddFlow(v,v+m+vn,gc);
                    if(j-1>=0) g.AddFlow(v,v-1+vn,gc);
                    if(j+1<m) g.AddFlow(v,v+1+vn,gc);
                }
                else
                {
                    g.AddFlow(v+vn,tt,w);
                }
                isLeft^=1;
            }
        }
        REP(i,n)
        {
            bool isLeft = ((i&1)==0);
            REP(j,m)
            {
                int w,v=GetV(i,j,m);
                scanf("%d",&w);
                sum+=w;
                if(isLeft)
                {
                    g.AddFlow(v+vn,tt,w);
                }
                else
                {
                    g.AddFlow(ss,v,w);
                    if(i-1>=0) g.AddFlow(v,v-m+vn,sc);
                    if(i+1<n) g.AddFlow(v,v+m+vn,sc);
                    if(j-1>=0) g.AddFlow(v,v-1+vn,sc);
                    if(j+1<m) g.AddFlow(v,v+1+vn,sc);
                }
                isLeft^=1;
            }
        }
        printf("Case %d: ",ca+1);
        cout<<sum-g.MaxFlow(ss,tt)<<endl;
    }
	return 0;
}
